The PhaseIPixelNtuplizer package (used to process the CMSSW output) is available at:
https://github.com/jkarancs/PhaseIPixelNtuplizer
The PhaseIEfficiencyPlotter package (used to create plots) is available at:
The loading of the toolkit, and opening of the input file is done here:
In [1]:
import ROOT, sys
ROOT.gStyle.SetPalette(1)
sys.path.append('../python/')
inputDir = "/data/hunyadi/CMSSW/PhaseIEfficiencyPlotter_2017_04_02/CMSSW_9_1_0_pre3/src/DPGAnalysis/PhaseIEfficiencyPlotter/"
inputFile = ROOT.TFile.Open(inputDir + "histograms_efficiency.root", "READ")
In [ ]:
mainDir = ROOT.gDirectory.Get(
ROOT.gDirectory.GetListOfKeys().First().GetTitle())
The file contains categorical plot type subdirectories. This is the list of all the categories:
In [ ]:
for index, subDir in enumerate(mainDir.GetListOfKeys()):
sys.stdout.write("%-49s " % subDir.GetTitle())
if index % 2 == 1: print ""
To draw the contents of these categories, a drawing tool is introduced here:
In [ ]:
def mergeCanvasRow(canvas, padIndex):
if padIndex % 2 == 0: print "Function mergeCanvasRow() was called on invalid taget."
original = canvas.cd(padIndex)
original.SetPad("centeredPad","centeredPad",
(1.0 - original.GetAbsWNDC()) / 2.0, original.GetAbsYlowNDC(),
(1.0 - original.GetAbsWNDC()) / 2.0 + original.GetAbsWNDC(), original.GetAbsYlowNDC() + original.GetAbsHNDC(), 0)
canvas.cd(padIndex + 1).Delete()
def renderToCanvases(name, title, width, height, plotDirectory, plotNames):
canvases = []
for index, plotName in enumerate(plotNames):
if index % 2 == 0:
canvases = canvases + [ROOT.TCanvas(name + "_%d" % (index / 2), title, width, height)]
canvases[-1].Divide(2, 1)
canvases[-1].cd((index % 2) + 1)
plot = ROOT.gDirectory.Get(plotDirectory + "/" + plotName)
if plot: plot.Draw("COLZ")
else: print "Missing plot: ", plotName
if(len(plotNames) % 2 == 1): mergeCanvasRow(canvases[-1], 1)
return canvases
The visualization of the is customized here:
In [ ]:
# ROOT.enableJSVis() # Uncommenting this adds interactive html/javascript elements to the notebook
ROOT.gStyle.SetPalette(1)
In [ ]:
canvases = renderToCanvases("ClusterOccupancyCanvas", "Cluster Occupancy on the ROCs", 900, 400,
mainDir.GetTitle() + "/" + "clusterOccupancyROCPlots",
["clusterOccupancyROCPlots_Layer1",
"clusterOccupancyROCPlots_Layer2",
"clusterOccupancyROCPlots_Layer3",
"clusterOccupancyROCPlots_Layer4",
"clusterOccupancyROCPlots_AllDisks"])
In [ ]:
canvases[0].Draw()
In [ ]:
canvases[1].Draw()
In [ ]:
canvases[2].Draw()
In [ ]:
canvases = renderToCanvases("ClusterPhiVsZCanvas", "Cluster occupancy, phi vs Z", 900, 400,
mainDir.GetTitle() + "/" + "clusterPhiVsZPlots",
["clusterPhiVsZPlots_Layer1",
"clusterPhiVsZPlots_Layer2",
"clusterPhiVsZPlots_Layer2",
"clusterPhiVsZPlots_Layer4"])
In [ ]:
canvases[0].Draw()
In [ ]:
canvases[1].Draw()
In [ ]:
canvases = renderToCanvases("ClusterGlyVsGlxCanvas", "Cluster occupancy, Y vs X", 900, 400,
mainDir.GetTitle() + "/" + "clusterGlyVsGlxPlots",
["clusterGlyVsGlxPlots_Disk1",
"clusterGlyVsGlxPlots_Disk2",
"clusterGlyVsGlxPlots_Disk3",
"clusterGlyVsGlxPlots_Disk4",
"clusterGlyVsGlxPlots_Disk5",
"clusterGlyVsGlxPlots_Disk6"])
In [ ]:
canvases[0].Draw()
In [ ]:
canvases[1].Draw()
In [ ]:
canvases[2].Draw()
In [ ]:
canvases = renderToCanvases("RechitOccupancyCanvas", "Rechit Occupancy on the ROCs", 900, 400,
mainDir.GetTitle() + "/" + "rechitOccupancyROCPlots",
["rechitOccupancyROCPlots_Layer1_Hits",
"rechitOccupancyROCPlots_Layer2_Hits",
"rechitOccupancyROCPlots_Layer3_Hits",
"rechitOccupancyROCPlots_Layer4_Hits",
"rechitOccupancyROCPlots_AllDisks_Hits"])
In [ ]:
canvases[0].Draw()
In [ ]:
canvases[1].Draw()
In [ ]:
canvases[2].Draw()
In [ ]:
canvases = renderToCanvases("rechitOccupancyPhiVsZCanvas", "Rechit occupancy, phi vs Z", 900, 400,
mainDir.GetTitle() + "/" + "rechitOccupancyPhiVsZPlots",
["rechitOccupancyPhiVsZPlots_Layer1_Hits",
"rechitOccupancyPhiVsZPlots_Layer2_Hits",
"rechitOccupancyPhiVsZPlots_Layer2_Hits",
"rechitOccupancyPhiVsZPlots_Layer4_Hits"])
In [ ]:
canvases[0].Draw()
In [ ]:
canvases[1].Draw()
In [ ]:
canvases = renderToCanvases("RechitOccupancyGlyVsGlxCanvas", "Rechit occupancy, Y vs X", 900, 450,
mainDir.GetTitle() + "/" + "rechitOccupancyGlyVsGlxPlots",
["rechitOccupancyGlyVsGlxPlots_Disk1_Hits",
"rechitOccupancyGlyVsGlxPlots_Disk4_Hits",
"rechitOccupancyGlyVsGlxPlots_Disk2_Hits",
"rechitOccupancyGlyVsGlxPlots_Disk5_Hits",
"rechitOccupancyGlyVsGlxPlots_Disk3_Hits",
"rechitOccupancyGlyVsGlxPlots_Disk6_Hits"])
In [ ]:
canvases[0].Draw()
In [ ]:
canvases[1].Draw()
In [ ]:
canvases[2].Draw()
The list of the cuts and their functions are listed here:
# | Cut name | Function |
---|---|---|
1 | nvtxCut | Discards tracks that come from a vertex with low number of tracks. |
2 | zerobiasCut | Discards trajectory measurements that come from non MinBias trigger selection (for data). |
3 | federrCut | Discards data when FED errors were present. |
4 | hpCut | Allows high-purity tracks only. |
5 | ptCut | Minimum track transverse momenta. |
6 | nstripCut | Number of strip hits required to validate the track presence. |
7 | d0Cut | Maximum track-vertex XY distance. |
8 | dzCut | Maximum track-vertex Z distance. |
9 | pixhitCut | Discards measurements with positions that have been propagated without a validhit in the adjacent detector layers/disks. |
10 | lxFidCut | Discards hits on the edges of the modules. For the forward section this is combined with the lyFidCut. |
11 | lyFidCut | Discards hits on the edges of the modules. For the forward section this is combined with the lxFidCut. |
12 | valmisCut | Discarding hits with invalid states. |
13 | hitsepCut | Discarding hits that have ambiguous track assignments (= there are more than one track traversing the detector near the hit). |
14 | badROCCut | Excluding non functioning modules and ROCs. |
Many of these cuts have different boundaries than the ones used in the Phase-0 scenario.
The fine-tuning of the cut values was an iterative process. In order to fine tune a single threshold, the other cuts should be present. The plots with all except one cut values pre-set are referred to as n - 1 plots. I used the Phase-0 cut values as the starting points of the iterations, where it was reasonable to do so.
In [ ]:
canvases = renderToCanvases("lyVsLxEfficiencyOnTheBarrelCanvas", "Ly vs lx efficiency on the barrel layers", 900, 400,
mainDir.GetTitle() + "/" + "lyVsLxEfficiencyWithCutsPlots",
["lyVsLxEfficiencyWithCutsPlots_Layer1_Eff.",
"lyVsLxEfficiencyWithCutsPlots_Layer2_Eff.",
"lyVsLxEfficiencyWithCutsPlots_Layer3_Eff.",
"lyVsLxEfficiencyWithCutsPlots_Layer4_Eff."])
In [ ]:
canvases[0].Draw()
In [ ]:
canvases[1].Draw()
As for the modules on the Pixel Endcaps, it is a completely different matter. Unfortunately, there are lots of different configurations for these modules for which the overlapping areas are completely different. As of the current state of the efficiency measurements, only the center of the forward modules were used, since this is the only place, where there are no overlaps between the adjacent modules. Unfortunately, this is a quite small proportion of the modules, so these cuts throw away most of the endcap trajectory measurements.
If you have any ideas how this approach can be upgraded/replaced, please make sure to comment on the matter! :)
For the orientation of the forward modules, 24 differerent scenarios were separated, and an area with correct efficiency measurement values were selected for each of them. Here I present only some of these cuts. The plots on the left side show the total n - 1 efficiencies. The plots on the right side present the efficiency values on the selected area only.
In [ ]:
preCutsNamePrefix = "forwardLocalPositionsByOrientationEfficiencyPlots"
postCutsNamePrefix = "forwardLocalPositionsByOrientationWithFidicualCutsEfficiencyPlots"
canvases = renderToCanvases("lyVsLxEfficiencyOnTheEndcapCanvas", "Ly vs lx efficiency on the endcap disks", 900, 400,
mainDir.GetTitle(),
["forwardLocalPositionsByOrientationEfficiencyPlots/" + preCutsNamePrefix + "_Disk1Efficiency_2",
"forwardLocalPositionsWithFidicualCutsEfficiencyPlots/" + postCutsNamePrefix + "_Disk1Efficiency_2",
"forwardLocalPositionsByOrientationEfficiencyPlots/" + preCutsNamePrefix + "_Disk1Efficiency_3",
"forwardLocalPositionsWithFidicualCutsEfficiencyPlots/" + postCutsNamePrefix + "_Disk1Efficiency_3",
"forwardLocalPositionsByOrientationEfficiencyPlots/" + preCutsNamePrefix + "_Disk2Efficiency_4",
"forwardLocalPositionsWithFidicualCutsEfficiencyPlots/" + postCutsNamePrefix + "_Disk2Efficiency_4"])
In [ ]:
canvases[0].Draw()
In [ ]:
canvases[1].Draw()
In [ ]:
canvases[2].Draw()
As for this cut, it was already introduced in the implementation of the PhaseIPixelNtuplizer. The cut value of 10 tracks seems to be perfectly reasonable.
In [ ]:
canvases = renderToCanvases("vtxNtrkEfficiencyWithCutsPlotsCanvas", "Number of tracks in the vertices", 900, 400,
mainDir.GetTitle() + "/" + "vtxNtrkEfficiencyWithCutsPlots",
["vtxNtrkEfficiencyWithCutsPlots_Hits",
"vtxNtrkEfficiencyWithCutsPlots_Eff."])
The Phase-0 value for this cut was set to 1.0. This value seems to be alll right and was kept.
In [ ]:
canvases = renderToCanvases("ptEfficiencyWithCutsPlotsCanvas", "Pt. of the traj. meas. tracks", 900, 400,
mainDir.GetTitle() + "/" + "ptEfficiencyWithCutsPlots",
["ptEfficiencyWithCutsPlots_Hits",
"ptEfficiencyWithCutsPlots_Eff."])
canvases[0].Draw()
The code used to plot the number of strip hits:
In [ ]:
canvases = renderToCanvases("striphitsEfficiencyWithCutsPlotsCanvas", "Strip hits for the traj. meas. tracks", 900, 400,
mainDir.GetTitle() + "/" + "striphitsEfficiencyWithCutsPlots",
["striphitsEfficiencyWithCutsPlots_Hits",
"striphitsEfficiencyWithCutsPlots_Eff.",])
In [ ]:
canvases[0].Draw()
The distribution of the number of strip hits is quite interesting. Most of the tracks with non-zero strip hits are located in a gaussian with a mean of ~14. Currently the cut value for the minimum number of strip hits is currently set to 10, this means, that most of the tracks in this region are kept.
The threshold used for the barrel modules and the forward modules were selected separately, since the error of the trajectory measurements on the layer is more dependent on the Z track-vertex distance, and as for the traj. measurements on the disks the precision is more dependent on the XY distance.
The current cut values for d0 of the layers are set to 0.01 on the first layer, and 0.02 on the other layers. There is also a cut value for dz, set to 0.1 just to throw away all the tracks with very bad vertex association.
In [ ]:
canvases = renderToCanvases("d0WithCutsPlotsAllLayersCanvas", "D0 of the traj. meas. tracks on the layers", 900, 400,
mainDir.GetTitle(),
["d0WithCutsPlots/d0WithCutsPlots_AllLayers_Hits",
"d0WithCutsPlots/d0WithCutsPlots_AllLayers_Eff.",
"dzWithCutsPlots/dzWithCutsPlots_AllLayers_Hits",
"dzWithCutsPlots/dzWithCutsPlots_AllLayers_Eff."])
In [ ]:
canvases[0].Draw()
In [ ]:
canvases[1].Draw()
In [ ]:
canvases = renderToCanvases("d0WithCutsPlotsAllDisksCanvas", "D0 of the traj. meas. tracks on the disks", 900, 400,
mainDir.GetTitle(),
["d0WithCutsPlots/d0WithCutsPlots_AllDisks_Hits",
"d0WithCutsPlots/d0WithCutsPlots_AllDisks_Eff.",
"dzWithCutsPlots/dzWithCutsPlots_AllDisks_Hits",
"dzWithCutsPlots/dzWithCutsPlots_AllDisks_Eff."])
In [ ]:
canvases[0].Draw()
In [ ]:
canvases[1].Draw()
In [ ]:
canvases = renderToCanvases("hitDistWithCutsPlotsCanvas", "Distance of closest non-parent track", 900, 400,
mainDir.GetTitle() + "/" + "hitDistWithCutsPlots",
["hitDistWithCutsPlots_Hits",
"hitDistWithCutsPlots_Eff.",])
canvases[0].Draw()
In [ ]:
canvases = renderToCanvases("clustDistWithCutsPlotsCanvas", "Traj. meas distance to the closest cluster", 900, 400,
mainDir.GetTitle() + "/" + "clustDistWithCutsPlots",
["clustDistWithCutsPlots_Hits",
"clustDistWithCutsPlots_Eff.",])
canvases[0].Draw()
In [ ]:
canvases = renderToCanvases("efficiencyMeasurementsCanvas", "Efficiency measurements", 900, 400,
mainDir.GetTitle() + "/" + "layersDisksEfficiencyPlots",
["layersDisksEfficiencyPlots_Hits",
"layersDisksEfficiencyPlots_Eff.",])
canvases[0].Draw()